﻿using System;
using System.Diagnostics;
using HashFoo.Core;
using HashFoo.SqlServer.Spatial;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace HashFoo.SqlServer.SpatialTests
{
    [TestClass]
    public class GeographyCreationTests
    {
        [TestMethod]
        public void point_type_is_returned_from_create_point()
        {
            var point = Geography.FromPoint(-80, 45);

            Assert.IsTrue(point.IsInstanceOf(GeometryType.Point));
        }

        [TestMethod]
        public void point_should_be_returned_from_wkt_point()
        {
            var wkt = WktResources.Point;

            var point = Geography.FromWkt(wkt);

            Assert.AreEqual(GeometryType.Point, point.GeometryType);
            Assert.AreEqual(wkt, point.AsWkt());
        }

        [TestMethod]
        public void multipoint_should_be_returned_from_explicit_wkt()
        {
            var wkt = WktResources.MultiPointExplicit;

            var points = Geography.FromWkt(wkt);

            Assert.AreEqual(GeometryType.MultiPoint, points.GeometryType);
            Assert.AreEqual(4, points.InternalGeography.STNumGeometries().Value);
        }

        [TestMethod]
        public void multipoint_should_be_returned_from_implicit_wkt()
        {
            var wkt = WktResources.MultiPointImplicit;

            var points = Geography.FromWkt(wkt);

            Assert.AreEqual(GeometryType.MultiPoint, points.GeometryType);
            Assert.AreEqual(4, points.InternalGeography.STNumGeometries().Value);
        }

        [TestMethod]
        public void linestring_is_returned_from_wkt()
        {
            var wkt = WktResources.LineString;

            var lineString = Geography.FromWkt(wkt);

            Assert.AreEqual(GeometryType.LineString, lineString.GeometryType);
            Assert.AreEqual(3, lineString.InternalGeography.STNumPoints().Value);
        }

        [TestMethod]
        public void multilinestring_is_returned_from_wkt()
        {
            var wkt = WktResources.MultiLineString;

            var lineString = Geography.FromWkt(wkt);

            Assert.AreEqual(GeometryType.MultiLineString, lineString.GeometryType);
            Assert.AreEqual(2, lineString.InternalGeography.STNumGeometries().Value);
        }

        [TestMethod]
        public void polygon_should_be_returned_from_wkt()
        {
            var wkt = WktResources.Polygon;

            var polygon = Geography.FromWkt(wkt);

            Assert.AreEqual(GeometryType.Polygon, polygon.GeometryType);
            // we don't do a wkt comparison here, becuase the SqlGeography
            // edits the point order of the interior ring...
            Assert.AreEqual(wkt, polygon.AsWkt());
        }

        [TestMethod]
        public void polygon_should_be_returned_from_wkt_polygon_with_inversed_ring()
        {
            var wkt = WktResources.PolygonWithInversedRing;

            var polygon = Geography.FromWkt(wkt);

            Assert.AreEqual(GeometryType.Polygon, polygon.GeometryType);
            Assert.AreEqual(WktResources.Polygon, polygon.AsWkt());
        }

        [TestMethod]
        public void polygon_with_hole_should_be_returned_from_wkt()
        {
            var wkt = WktResources.PolygonWithHole;

            var polygon = Geography.FromWkt(wkt);

            Assert.AreEqual(GeometryType.Polygon, polygon.GeometryType);
            Assert.AreEqual(2, polygon.NumberOfRings);
        }

        [TestMethod]
        public void polygon_with_hole_should_be_returned_from_wkt_with_inversed_rings()
        {
            var wkt = WktResources.PolygonWithHoleWithInversedRings;

            var polygon = Geography.FromWkt(wkt);

            Assert.AreEqual(GeometryType.Polygon, polygon.GeometryType);
            Assert.AreEqual(2, polygon.NumberOfRings);
        }

        [TestMethod]
        public void multipolygon_is_returned_from_wkt()
        {
            var wkt = WktResources.MultiPolygon;

            var polygon = Geography.FromWkt(wkt);

            Assert.AreEqual(GeometryType.MultiPolygon, polygon.GeometryType);
            Assert.AreEqual(2, polygon.InternalGeography.STNumGeometries().Value);
        }

        [TestMethod]
        public void multipolygon_with_hole_is_returned_from_wkt()
        {
            var wkt = WktResources.MultiPolygonWithHole;

            var polygon = Geography.FromWkt(wkt);

            Assert.AreEqual(GeometryType.MultiPolygon, polygon.GeometryType);
            Assert.AreEqual(2, polygon.InternalGeography.STNumGeometries().Value);
        }

        [TestMethod]
        public void sqlserver_udt_binary_can_be_converted_to_geography()
        {
            // polygon with hole binary
            const string binaryString = "0xE6100000010409000000000000000000244000000000008041400000000000804640000000000080464000000000000044400000000000002E4000000000000034400000000000002440000000000000244000000000008041400000000000003E4000000000000034400000000000804140000000000080414000000000000034400000000000003E400000000000003E400000000000003440020000000200000000000500000001000000FFFFFFFF0000000003";

            var geography = Geography.FromSqlServer(ConvertUtil.StringToByteArray(binaryString));

            Assert.IsNotNull(geography);
            Assert.AreEqual(GeometryType.Polygon, geography.GeometryType);
            Assert.AreEqual(2, geography.NumberOfRings);
        }

        [TestMethod]
        public void two_corner_points_create_a_square_polygon()
        {
            const int xmin = 5;
            const int xmax = 10;
            const int ymin = 5;
            const int ymax = 10;

            var geography = Geography.CreateSquarePolygon(xmin, ymin, xmax, ymax);

            Assert.AreEqual(1, geography.NumberOfRings);
            Assert.AreEqual(4326, geography.Srid);
        }
    }
}
